package com.cata.mall.security.component;

import cn.hutool.core.collection.CollUtil;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;

/**
 * @作者: Tao
 * @日期: 2025/10/11
 * @时间: 10:45
 * @描述: 动态权限决策管理器，用于判断用户是否有访问权限<pre>
 */
public class DynamicAccessDecisionManager implements AccessDecisionManager {

    /**
     * 决定当前认证用户是否有权限访问指定资源
     *
     * @param authentication   当前用户的认证信息，包含用户的身份和权限集合
     * @param object           被访问的资源对象（如URL、方法等）
     * @param configAttributes 访问该资源所需的配置属性（权限要求）
     * @throws AccessDeniedException               当用户没有足够权限访问资源时抛出
     * @throws InsufficientAuthenticationException 当认证信息不充分时抛出
     */
    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        // 当接口未被配置资源时直接放行
        if (CollUtil.isEmpty(configAttributes)) {
            return;
        }

        // 遍历所有配置的访问权限要求
        for (ConfigAttribute configAttribute : configAttributes) {
            //将访问所需资源或用户拥有资源进行比对
            String needAuthority = configAttribute.getAttribute();

            // 检查用户是否拥有访问所需的权限
            for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
                if (needAuthority.trim().equals(grantedAuthority.getAuthority())) {
                    return;
                }
            }
        }

        // 用户没有任何匹配的权限，拒绝访问
        throw new AccessDeniedException("抱歉，您没有访问权限");
    }


    /**
     * 判断是否支持指定的安全配置属性
     *
     * @param attribute 安全配置属性对象
     * @return 总是返回true，表示支持所有配置属性
     */
    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    /**
     * 判断是否支持指定的类类型
     *
     * @param clazz 需要检查的类类型
     * @return 总是返回true，表示支持所有类类型
     */
    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }

}
